17-3 HROCD

以指令列為主的除錯函數可用於各種不同平台,其功能可列表如下:

語法功能
dbstop at line# in filename 設定中斷點(Break Points)
(line# 代表行號,filename 代表檔案名稱)
dbclear at line# in filename 清除中斷點
(line#代表行號,filename 代表檔案名稱)
dbstop if warning 若遇到下列情況,則暫停程式執行:
  • 警告(Warning)
  • 錯誤(Error)
  • 非數值/無窮大(NaN/Inf)
dbstop if error
dbstop if naninf
dbstop if infnan
dbcont 從暫停狀態繼續執行
dbstack 列出函數呼叫過程中的堆疊
dbstatus filename 列出某檔案的所有中斷點
(filename 代表檔案名稱)
dbstep n 執行 n 列指令
dbtype filename 列出檔案內容(包含每列編號)
(filename 代表檔案名稱)
dbdown 向下進入局部的工作空間
dbup 向上進入呼叫端的工作空間
dbquit 離開除錯模式

在上述的除錯指令中,最重要的指令就是 dbstop,我們可以利用這個指令來指定程式碼的中斷點(Break Points),使得 MATLAB 可在中斷點前停止執行,以讓我們能檢查各個局部變數的值。dbstop 的一般格式及相關說明可列表如下:

指令格式說明
dbstop in filename at line# 停止執行於某檔案的某行
(filename 代表檔案名稱,line#代表行號)
dbstop in filename at subfunction 停止執行於某檔案的次函數
(filename 代表檔案名稱)
dbstop in filename 停止執行於某檔案
(filename 代表檔案名稱)
dbstop if error 若出現錯誤,則暫停程式執行,並停留在發生錯誤的工作空間
dbstop if warning 若出現警告,則暫停程式執行,並停留在發生警告的工作空間
dbstop if naninf 若出現 nan 或 inf,則暫停程式執行,並停留在發生 nan 或 inf的工作空間
dbstop if infnan (同上)

在上表中,in、at 和 if 都可以省略,所以「dbstop in testfunc at 15」可以簡寫成「dbstop testfunc 15」。

一旦程式停止執行後,MATLAB 就進入所謂的 「除錯模式」(Debugging Mode),指令列上會出現“k>>”的提示號,代表此時可以接受鍵盤輸入。如果您使用的平台是 PC 或 MAC,同時也會出現 M 檔案除錯器(M-file Debugger),可直接檢視程式出錯的部分。有關於 M 檔案除錯器的細節,將會在下一節詳細介紹,本節則以介紹指令列的除錯指令為主。

進入除錯模式後,我們可檢查任何變數的值,也可以執行其他任何指令或手稿(Scripts)。檢查完畢後,可能採取的動作可列舉如下:

指令格式說明
dbcont 繼續執行程式
dbstep n 執行 n 列程式碼
dbtype filename 列出程式碼
(filename 代表程式檔案名稱)
dbdown 向下切換至另一個工作空間
dbup 向上切換至另一個工作空間
dbstack 列出函數呼叫過程中的堆疊
dbquit 跳出除錯模式

在上表中,最常用到的指令是 dbstep,可以讓我們一次執行一列或多列程式碼,或是進入或跳出一個指令的內部程式碼,其格式可列舉如下:

指令格式說明
dbstep 執行下一列程式碼
dbstep n 執行下 n 列程式碼
dbstep in 進入下一列指令的程式碼
dbstep out 跳出目前指令的程式碼

其他各除錯指令的格式較固定,欲取得更多資訊,可由 MATLAB 線上支援取得。

另外,dbclear 及 dbstatus 可用於一般模式及除錯模式。dbclear 用於取消中斷點,和 dbstop 的功能恰好相反,dbclear 的使用格式可參見本節的第一個表格(即 dbstop 的使用格式),只需將所有的 dbstop 改為 dbclear 即可。

此外,若要清除所有的中斷點,可用 dbclear all。

dbstatus 可列出所有的中斷點,其格式如下:

指令格式說明
dbstatus 列出所有中斷點
dbstatus filename 列出在一檔案中的中斷點
(filename 代表程式檔案名稱)
s = dbstatus(…) 將中斷點的資訊傳回變數 s

以下將以實例來說明這些除錯指令的運用。

假設我們要計算一向量的倒數和,可使用名稱為 recipsum.m 的函數,如下:

>> type recipsum function out = recipsum(x) recip = reciproc(x); out = sum(recip); function output = reciproc(input) output = 1./x;

此函數包含一錯誤,執行時即會出現:

>> recipsum([1 2 3]) Undefined function or variable 'x'. Error in recipsum>reciproc (line 7) output = 1./x; Error in recipsum (line 3) recip = reciproc(x);

Hint
本範例的錯誤訊息,是以 MATLAB 8.5 版為主。不同版本的 MATLAB,可能產生不同的錯誤訊息,但是都大同小異。

此錯誤訊息是由次函數 reciproc 所產生。為了偵錯方便,當錯誤訊息發生時,我們可以讓 MATLAB 仍然能夠停留在產生錯誤訊息的函數,所使用的指令如下:

>> dbstop if error

可用 dbstop 來確認所建立的中斷條件:

>> dbstatus Stop if error.

此時可再呼叫原函數:

>> recipsum([1 2 3])

MATLAB 這次會停在錯誤發生的程式碼,並將之顥示於 MATLAB 除錯器(也是 MATLAB 編輯器),如下:

此時我們可在指令視窗使用 dbstack 來顯示 MATLAB 所在的函數:

k>> dbstack > In recipsum>reciproc (line 7) In recipsum (line 3)

亦可用 dbtype 來顯示程式碼:

k>> dbtype recipsum 1 function out = recipsum(x) 2 3 recip = reciproc(x); 4 out = sum(recip); 5 6 function output = reciproc(input) 7 output = 1./x;

很明顯地,在 reciproc 次函數中的變數 x 並未定義,因此我們可在除錯器中直接將 x 改成 input ,並儲存此檔案於 recipsum1.m,就完成了除錯的工作。此時再進行函數呼叫,就可得到正確答案:

k>> dbquit % 離開除錯模式 >> recipsum1([1 2 3]) ans = 1.8333

Hint
一旦在除錯器進行編輯檔案的動作,MATLAB 就會跳出除錯模式,準備再次執行除錯後的程式碼。

上例的錯誤是相當顯而易見,但如果遇到較複雜錯誤,就必需在程式碼停止後,在指令列逐一檢查可能出問題的變數,直到找出問題所在之後,再進行程式碼的修改:

此外,當程式暫停執行於一個函數時,我們也可以使用 dbup 及 dbdown 來跳到不同的工作空間,以便檢視各變數。

假設在 recipsum.m 的錯誤已修正完畢,修正後的檔案是 recipsum1.m,我們還是可能遇到其他問題,例如:

>> recipsum1([2 0 2]) ans = Inf

此時傳回答案為 Inf(無窮大),這並不是我們預期的答案(假設我們並沒有預期到使用者會輸入含有 0 的向量)。為探查錯誤所在,我們設立另一個中斷條件,並再次呼叫函數:

>> dbstop if naninf >> recipsum1([2 0 2]) NaN/Inf breakpoint hit for recipsum1>reciproc on line 7. 7 output = 1./input;

很明顯地,在計算 0 的倒數時,出現了 Inf。我們假設在輸入為 0 時,其倒數不計,則程式碼可修正如下:

k>> dbquit % 離開除錯模式 >> type recipsum2 function out = recipsum(x) recip = reciproc(x); out = sum(recip); function output = reciproc(input) input(find(input==0)) = []; % Eliminate "0" elements output = 1./input;

此時再呼叫函數,就可以產生我們預期的結果:

>> recipsum2([2 0 2]) ans = 1

Hint
在進行大量繁瑣的數值運算時,欲偵測 Nan 或 Inf 的產生,使用「dbstop if naninf 」最適合!


MATLAB程式設計:入門篇